/*
* All scene graph objects are derived from this class
*/
#include "SceneNode.h"

#include "DirectXEngine.h"

SceneNode::SceneNode()
{
	position = new D3DXVECTOR3(0.0, 0.0, 0.0);
	rotation = new D3DXVECTOR3(0.0, 0.0, 0.0);
	velocity = new D3DXVECTOR3(0.0, 0.0, 0.0);
	scale = new D3DXVECTOR3(1.0, 1.0, 1.0);

	shape = NULL;
	parent = NULL;

	name = L"SceneNode";

	isVisible = true;
}

SceneNode::SceneNode(Shape * s)
{
	SceneNode();

	shape = s;
}

SceneNode::~SceneNode() {}

void SceneNode::Release() 
{ 
	delete this; 
}

// update our scene node
void SceneNode::Update(double frameTime)
{

	position->x += (velocity->x * frameTime);
	position->y += (velocity->y * frameTime);
	position->z += (velocity->z * frameTime);

	//TODO: rotation stuff

	// loop through the list and update the children
	for( std::list<SceneNode*>::iterator i = m_lstChildren.begin(); i != m_lstChildren.end(); i++ )
	{
		(*i)->Update(frameTime);
	}
}

void SceneNode::Draw()
{	
	//TODO: may need to load the identity matrix
	//D3DXMATRIX* D3DXMatrixIdentity(D3DXMATRIX* pOut);

	    // set the world transform
    D3DXMATRIX matRotateX;    // a matrix to store the rotation for each triangle
    D3DXMATRIX matRotateY;    // a matrix to store the rotation for each triangle
    D3DXMATRIX matRotateZ;    // a matrix to store the rotation for each triangle

	D3DXMATRIX matScale;

	D3DXMATRIX matTranslate;
	
	D3DXMatrixRotationX(&matRotateX, rotation->x);
	D3DXMatrixRotationY(&matRotateY, rotation->y);    // the rotation matrix
	D3DXMatrixRotationZ(&matRotateZ, rotation->z);

	D3DXMATRIX matRotationXYZ = matRotateX * matRotateY * matRotateZ;

	D3DXMatrixScaling(&matScale, scale->x, scale->y, scale->z);

	D3DXMatrixTranslation(&matTranslate, position->x, position->y, position->z);

	
	//parent matrix
	D3DXMATRIX parMatRotateX;    
	D3DXMATRIX parMatRotateY;    
	D3DXMATRIX parMatRotateZ;   

	D3DXMATRIX parMatScale;

	D3DXMATRIX parMatTranslate;

	//FIXME: not really the nicest way to do inheited position but seems to work
	if (parent != NULL )
	{		
		D3DXMatrixRotationX(&parMatRotateX, parent->rotation->x);
		D3DXMatrixRotationY(&parMatRotateY, parent->rotation->y);    // the rotation matrix
		D3DXMatrixRotationZ(&parMatRotateZ, parent->rotation->z);

		D3DXMATRIX parMatRotationXYZ = parMatRotateX * parMatRotateY * parMatRotateZ;

		D3DXMatrixScaling(&parMatScale, parent->scale->x, parent->scale->y, parent->scale->z);

		D3DXMatrixTranslation(&parMatTranslate, parent->position->x, parent->position->y, parent->position->z);

		CDirectXEngine::Instance()->d3ddev->SetTransform(D3DTS_WORLD, &(parMatRotationXYZ * matRotationXYZ
																		* parMatScale * matScale
																		* parMatTranslate * matTranslate
																		)
														 );    // set the world transform

	}
	else
	{
		CDirectXEngine::Instance()->d3ddev->SetTransform(D3DTS_WORLD, &(matRotationXYZ * matScale * matTranslate));    // set the world transform
	}


	//Draw the shape
	if (shape != NULL && isVisible)
		shape->Draw();

	// loop through the list and update the children
	for( std::list<SceneNode*>::iterator i = m_lstChildren.begin(); i != m_lstChildren.end(); i++ )
	{
	  (*i)->Draw();
	}
	
}

// destroy all the children
void SceneNode::Destroy()
{	//FIXME: dont think this method is right
	for( std::list<SceneNode*>::iterator i = m_lstChildren.begin(); i != m_lstChildren.end(); i++ )
		(*i)->Release();

	 m_lstChildren.clear();
}

  // add a child to our custody
void SceneNode::AddChild( SceneNode* pNode )
{
	pNode->parent = this;
	m_lstChildren.push_back(pNode);
}

void SceneNode::UpdatePosition(D3DXVECTOR3 pos)
{
	position = &pos;
}

void SceneNode::UpdatePosition(float xpos, float ypos, float zpos)
{
	position->x += xpos;
	position->y += ypos;
	position->z += zpos;
}

void SceneNode::SetAcceleration(D3DXVECTOR3 accl)
{

}

void SceneNode::SetVelocity(D3DXVECTOR3 vel)
{
	*velocity = vel;	
}

void SceneNode::SetVelocity(float x, float y, float z)
{
	velocity->x = x;
	velocity->y = y;
	velocity->z = z;
}

void SceneNode::SetPosition(float x, float y, float z)
{
	position->x = x;
	position->y = y;
	position->z = z;
}

void SceneNode::SetScale(float x, float y, float z)
{
	scale->x = x;
	scale->y = y;
	scale->z = z;
}

void SceneNode::SetVisible(bool isVisible)
{
	this->isVisible = isVisible;
}